package com.tony.jdbc.dynamic.aspect;

import com.tony.jdbc.dynamic.annotation.DynamicDatasource;
import com.tony.jdbc.dynamic.datasource.DynamicDataSourceKeyHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author tony
 * @desc 数据源切面
 * 注意：需要通过Order注解保证在Spring Boot的默认事务拦截器TransactionInterceptor处理前执行，如果默认事务拦截器先执行，拿到默认数据源的连接。
 * Spring默认事务顺序在EnableTransactionManagement里定义为：Ordered.LOWEST_PRECEDENCE。
 * @date 2025/10/27 12:51
 */
@Aspect
@Component
@Order(Ordered.LOWEST_PRECEDENCE - 1) // 设置高优先级，确保在 JpaTransactionManager 之前执行
public class DynamicDatasourceAspect {
    /**
     * 切面方法，在目标方法执行之前设置数据源
     */
    @Before("execution(* com.tony.jdbc.dynamic.service.*.*(..))||execution(* com.tony.jdbc.dynamic.controller.*.*(..))")
    public void setDatasource(JoinPoint joinPoint) {
        System.out.println("Before execution");
        //读取方法上得注解，并设置数据源
        // 获取目标方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 查找方法上的 DataSource 注解
        DynamicDatasource annotation = method.getAnnotation(DynamicDatasource.class);
        if (annotation == null) {
            // 获取目标对象及其类
            Object target = joinPoint.getTarget();
            Class<?> targetClass = target.getClass();
            //获取类上注解
            annotation = targetClass.getAnnotation(DynamicDatasource.class);
        }
        if (annotation != null) {
            // 设置数据源到上下文持有者
            DynamicDataSourceKeyHolder.setKey(annotation.value());
        }
    }

    /**
     * 切面方法，在目标方法执行之后移除数据源
     */
    @After("execution(* com.tony.jdbc.dynamic.service.*.*(..))||execution(* com.tony.jdbc.dynamic.controller.*.*(..))")
    public void removeDatasource() {
        System.out.println("After execution");
        DynamicDataSourceKeyHolder.removeKey();
    }
}
